<template>
  <el-dialog
    v-model="dialogVisible"
    :title="false"
    :show-close="false"
    width="70%"
    :close-on-click-modal="false"
    :before-close="handleClose"
    class="ai-chat-dialog"
    top="5vh"
    destroy-on-close
  >
    <template #header>
      <div class="dialog-header">
        <div class="dialog-title">
          <el-icon class="title-icon"><ChatDotRound /></el-icon>
          <span>AI 智能助手</span>
        </div>
        <el-button
          class="close-btn"
          icon="Close"
          circle
          @click="handleClose"
        />
      </div>
    </template>
    <div class="chat-container">
      <!-- 连接状态显示和模型选择 -->
      <div class="chat-header">
        <div class="connection-status" :class="{ connected: isConnected }">
          <el-icon class="status-icon"><Connection /></el-icon>
          {{ isConnected ? 'AI 服务已连接' : '正在连接 AI 服务...' }}
          <div v-if="!isConnected" class="connection-actions">
            <el-tooltip content="重新尝试自动连接" placement="top">
              <el-button 
                v-if="reconnectFailed" 
                size="small" 
                type="primary" 
                @click="retryConnection"
                class="retry-btn action-btn"
                :loading="isConnecting"
              >
                <el-icon class="action-icon" v-if="!isConnecting"><RefreshRight /></el-icon>
                <span>重试连接</span>
              </el-button>
            </el-tooltip>
            <el-tooltip content="手动建立连接" placement="top">
              <el-button 
                size="small" 
                type="success" 
                @click="manualConnect"
                class="manual-connect-btn action-btn"
                :loading="isConnecting"
              >
                <el-icon class="action-icon" v-if="!isConnecting"><Link /></el-icon>
                <span>手动连接</span>
              </el-button>
            </el-tooltip>
          </div>
        </div>
        <div class="model-selector">
          <span class="model-label">模型:</span>
          <el-select 
            v-model="selectedModel" 
            placeholder="选择模型" 
            size="small"
            :disabled="isThinking"
            class="model-select"
          >
            <el-option
              v-for="item in modelOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </div>
        <div class="chat-mode-switch">
          <span class="mode-label">连续对话:</span>
          <el-switch
            v-model="continuousMode"
            :disabled="isThinking"
            active-color="#67c23a"
            inactive-color="#909399"
          />
          <el-tooltip content="查看对话上下文" placement="top" v-if="continuousMode">
            <el-button 
              type="info" 
              size="small" 
              circle 
              @click="showContextDialog"
              :disabled="messages.length < 2"
              class="context-btn"
            >
              <el-icon><InfoFilled /></el-icon>
            </el-button>
          </el-tooltip>
        </div>
      </div>

      <!-- 聊天记录区域 -->
      <div class="chat-messages" ref="messagesContainer">
        <transition-group name="message-fade">
          <div v-for="(message, index) in messages" :key="index" 
               :class="['message', message.role === 'user' ? 'user-message' : (message.role === 'reasoning' ? 'reasoning-message' : 'ai-message')]">
            <div class="avatar" v-if="message.role !== 'reasoning'">
              <el-avatar :size="36" :icon="message.role === 'user' ? 'User' : 'ChatDotRound'" 
                        :class="message.role === 'user' ? 'user-avatar' : 'ai-avatar'" />
            </div>
            <template v-if="message.role === 'reasoning'">
              <div class="reasoning-container">
                <div class="reasoning-header">
                  <el-icon><Cpu /></el-icon>
                  <span>AI 推理过程</span>
                </div>
                <div class="reasoning-text">{{ message.content }}</div>
              </div>
            </template>
            <div v-else class="message-content">
              <div v-if="message.role === 'user'" class="user-content">
                {{ message.content }}
                <div class="user-message-actions">
                  <el-tooltip content="重新发送" placement="top">
                    <el-button 
                      type="primary" 
                      size="small" 
                      circle 
                      @click="resendMessage(message.content)"
                      :disabled="isThinking"
                    >
                      <el-icon><RefreshRight /></el-icon>
                    </el-button>
                  </el-tooltip>
                  <el-tooltip content="编辑后重发" placement="top">
                    <el-button 
                      type="warning" 
                      size="small" 
                      circle 
                      @click="editAndResend(message.content)"
                      :disabled="isThinking"
                    >
                      <el-icon><EditPen /></el-icon>
                    </el-button>
                  </el-tooltip>
                  <el-tooltip content="复制到剪贴板" placement="top">
                    <el-button 
                      type="info" 
                      size="small" 
                      circle 
                      @click="copyMessage(message.content)"
                    >
                      <el-icon><DocumentCopy /></el-icon>
                    </el-button>
                  </el-tooltip>
                </div>
              </div>
              <div v-else class="ai-content markdown-body" v-html="renderMarkdown(message.content)">
              </div>
              <div v-if="message.role === 'assistant'" class="message-actions">
                <el-tooltip content="复制回答" placement="top">
                  <el-button 
                    type="primary" 
                    size="small" 
                    circle 
                    @click="copyMessage(message.content)"
                  >
                    <el-icon><DocumentCopy /></el-icon>
                  </el-button>
                </el-tooltip>
                <el-tooltip content="提取代码" placement="top" v-if="hasCode(message.content)">
                  <el-button 
                    type="success" 
                    size="small" 
                    circle 
                    @click="extractCode(message.content)"
                  >
                    <el-icon><Document /></el-icon>
                  </el-button>
                </el-tooltip>
              </div>
              <div class="message-time" v-if="message.role !== 'reasoning'">
                {{ formatTime(message.timestamp) }}
              </div>
            </div>
          </div>
        </transition-group>
        <div v-if="isThinking" class="message ai-message">
          <div class="avatar">
            <el-avatar :size="36" icon="ChatDotRound" class="ai-avatar" />
          </div>
          <div class="message-content thinking-content">
            <div class="thinking-indicator-container">
              <div class="thinking-status">AI 正在思考中</div>
              <div class="typing-indicator">
                <span></span>
                <span></span>
                <span></span>
              </div>
            </div>
            <el-button 
              type="danger" 
              size="small" 
              @click="stopGeneration"
              class="stop-btn"
            >
              <el-icon><CircleClose /></el-icon>
              <span>停止生成</span>
            </el-button>
          </div>
        </div>
        <div v-if="messages.length === 0 && !isThinking" class="empty-state">
          <el-icon class="empty-icon"><ChatDotRound /></el-icon>
          <p>开始与 AI 助手对话吧</p>
          <p class="empty-hint">选择合适的模型，输入您的问题</p>
        </div>
      </div>

      <!-- 输入区域 -->
      <div class="chat-input">
        <el-input
          v-model="userInput"
          type="textarea"
          :rows="3"
          placeholder="请输入您的问题..."
          :disabled="!isConnected || isThinking"
          @keyup.enter.ctrl="handleSend"
          resize="none"
          class="input-textarea"
        />
        <div class="input-actions">
          <div class="left-actions">
            <el-tooltip content="清空对话" placement="top">
              <el-button 
                type="danger" 
                plain 
                size="small" 
                @click="clearMessages"
                :disabled="messages.length === 0"
                class="action-btn"
              >
                <el-icon><Delete /></el-icon>
                <span>清空</span>
              </el-button>
            </el-tooltip>
            <el-tooltip content="保存对话" placement="top">
              <el-button 
                type="success" 
                plain 
                size="small" 
                @click="saveConversation"
                :disabled="messages.length === 0"
                class="action-btn"
              >
                <el-icon><Download /></el-icon>
                <span>保存</span>
              </el-button>
            </el-tooltip>
            <el-tooltip content="新对话" placement="top">
              <el-button 
                type="info" 
                plain 
                size="small" 
                @click="startNewChat"
                :disabled="messages.length === 0"
                class="action-btn"
              >
                <el-icon><Plus /></el-icon>
                <span>新对话</span>
              </el-button>
            </el-tooltip>
          </div>
          <div class="right-actions">
            <span class="hint">Ctrl + Enter 发送</span>
            <el-button 
              type="primary" 
              @click="handleSend"
              :loading="isThinking"
              :disabled="!isConnected || !userInput.trim()"
              class="send-btn"
            >
              <el-icon class="send-icon"><Position /></el-icon>
              发送
            </el-button>
          </div>
        </div>
      </div>
    </div>

    <!-- 代码提取对话框 -->
    <el-dialog
      v-model="codeDialogVisible"
      title="提取的代码"
      width="50%"
      append-to-body
      destroy-on-close
      class="code-extract-dialog"
    >
      <div class="code-tabs">
        <el-tabs v-model="activeCodeTab" type="card">
          <el-tab-pane 
            v-for="(code, index) in extractedCodes" 
            :key="index"
            :label="getCodeLanguage(code) || `代码片段 ${index + 1}`"
            :name="String(index)"
          >
            <div class="code-block-wrapper">
              <div class="code-block-header">
                <span class="code-language">{{ getCodeLanguage(code) || '未知语言' }}</span>
                <div class="code-actions">
                  <el-tooltip content="复制代码" placement="top">
                    <el-button 
                      type="primary" 
                      size="small" 
                      @click="copyCode(code)"
                      class="code-action-btn"
                    >
                      <el-icon><DocumentCopy /></el-icon>
                      <span>复制</span>
                    </el-button>
                  </el-tooltip>
                  <el-tooltip content="下载代码" placement="top">
                    <el-button 
                      type="success" 
                      size="small" 
                      @click="downloadCode(code, index)"
                      class="code-action-btn"
                    >
                      <el-icon><Download /></el-icon>
                      <span>下载</span>
                    </el-button>
                  </el-tooltip>
                </div>
              </div>
              <div class="code-content-wrapper">
                <pre class="code-content"><code class="hljs" :class="code.language ? `language-${code.language}` : ''" v-html="highlightCode(code)"></code></pre>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
    </el-dialog>

    <!-- 对话上下文对话框 -->
    <el-dialog
      v-model="contextDialogVisible"
      title="当前对话上下文"
      width="50%"
      append-to-body
      destroy-on-close
      class="context-dialog"
    >
      <div class="context-info">
        <p class="context-description">
          连续对话模式下，AI 会记住以下对话历史（按时间顺序）：
        </p>
        <div class="context-messages-wrapper">
          <div class="context-messages">
            <div v-for="(msg, index) in contextMessages" :key="index" class="context-message">
              <div class="context-message-header">
                <span class="context-role">{{ msg.role === 'user' ? '用户' : 'AI 助手' }}</span>
                <span class="context-time">{{ formatTime(msg.timestamp) }}</span>
              </div>
              <div class="context-content">{{ msg.content }}</div>
            </div>
          </div>
        </div>
        <div class="context-tokens">
          <p>当前对话上下文约包含 {{ estimateTokenCount }} 个标记 (tokens)</p>
        </div>
      </div>
    </el-dialog>
  </el-dialog>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { 
  Loading, 
  Connection, 
  DocumentCopy, 
  Delete, 
  Download, 
  ChatDotRound, 
  Position,
  Close,
  User,
  Document,
  Plus,
  InfoFilled,
  RefreshRight,
  EditPen,
  CircleClose,
  Cpu,
  Link
} from '@element-plus/icons-vue'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css' // 可以选择其他样式，如 'atom-one-dark.css'
import config from "@/config"

const props = defineProps({
  modelValue: Boolean,
  initialPrompt: {
    type: String,
    default: ''
  },
  websocketUrl: {
    type: String,
    default: config.AI_URL
  }
})

const emit = defineEmits(['update:modelValue'])

// 状态
const userInput = ref('')
const messages = ref([])
const isThinking = ref(false)
const isConnected = ref(false)
const reconnectFailed = ref(false)
const messagesContainer = ref(null)
let ws = null
let reconnectAttempts = 0
const MAX_RECONNECT_ATTEMPTS = 5
let initialPromptSent = false
let reconnectTimer = null
const isConnecting = ref(false)

// 连续对话模式
const continuousMode = ref(true)

// 代码提取相关
const codeDialogVisible = ref(false)
const extractedCodes = ref([])
const activeCodeTab = ref('0')

// 对话上下文相关
const contextDialogVisible = ref(false)
const contextMessages = computed(() => {
  return messages.value
    .filter(msg => msg.role === 'user' || msg.role === 'assistant')
    .sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp))
})

// 估算token数量（粗略估计，每4个字符约为1个token）
const estimateTokenCount = computed(() => {
  let totalChars = 0
  contextMessages.value.forEach(msg => {
    totalChars += msg.content.length
  })
  return Math.ceil(totalChars / 4)
})

// 模型选择
const modelOptions = [
  { value: 'ep-20250204163109-jw9ch', label: 'Doubao-1.5-pro-256k' },
  { value: 'ep-20250204162538-9cmb2', label: 'DeepSeek-R1' },
  { value: 'ep-20250204190620-9n94t', label: 'DeepSeek-V3' },
  { value: 'ep-20250219225638-x9wwt', label: 'DeepSeek-R1-32B' },


]
const selectedModel = ref('ep-20250204190620-9n94t')

// Markdown 渲染器
const md = new MarkdownIt({
  html: true,
  breaks: true,
  linkify: true,
  highlight: function (str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        const highlighted = hljs.highlight(str, { language: lang, ignoreIllegals: true }).value;
        return `<pre data-lang="${lang}"><code class="hljs language-${lang}">${highlighted}</code></pre>`;
      } catch (e) {
        console.error("代码高亮错误:", e);
      }
    }
    return `<pre data-lang="${lang || ''}"><code class="hljs">${md.utils.escapeHtml(str)}</code></pre>`;
  }
})

// 计算属性
const dialogVisible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
})

// 渲染 Markdown
const renderMarkdown = (content) => {
  return md.render(content)
}

// 滚动到底部
const scrollToBottom = async () => {
  await nextTick()
  if (messagesContainer.value) {
    messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
  }
}

// 复制消息
const copyMessage = (content) => {
  // 创建一个临时textarea元素
  const textarea = document.createElement('textarea')
  textarea.value = content
  document.body.appendChild(textarea)
  textarea.select()
  
  try {
    // 执行复制命令
    document.execCommand('copy')
    ElMessage.success('已复制到剪贴板')
  } catch (err) {
    ElMessage.error('复制失败，请手动复制')
  } finally {
    document.body.removeChild(textarea)
  }
}

// 清空消息
const clearMessages = () => {
  if (messages.value.length > 0) {
    ElMessage.success('对话已清空')
    messages.value = []
  }
}

// 开始新对话
const startNewChat = () => {
  if (isThinking.value) {
    ElMessage.warning('正在等待AI响应，请稍候...')
    return
  }
  
  messages.value = []
  userInput.value = ''
  ElMessage.success('已开始新对话')
}

// 保存对话
const saveConversation = () => {
  if (messages.value.length === 0) return
  
  // 格式化对话内容
  let content = '# AI 对话记录\n\n'
  content += `时间: ${new Date().toLocaleString()}\n`
  content += `模型: ${selectedModel.value}\n\n`
  
  messages.value.forEach(msg => {
    if (msg.role === 'user') {
      content += `## 用户\n\n${msg.content}\n\n`
    } else if (msg.role === 'assistant') {
      content += `## AI 助手\n\n${msg.content}\n\n`
    }
  })
  
  // 创建下载链接
  const blob = new Blob([content], { type: 'text/markdown' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = `AI对话记录_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.md`
  document.body.appendChild(a)
  a.click()
  
  // 清理
  setTimeout(() => {
    document.body.removeChild(a)
    URL.revokeObjectURL(url)
  }, 100)
  
  ElMessage.success('对话已保存')
}

// 检查消息中是否包含代码块
const hasCode = (content) => {
  return content.includes('```')
}

// 提取代码块
const extractCode = (content) => {
  const codeBlockRegex = /```(?:([\w-]+)\n)?([\s\S]*?)```/g
  const codes = []
  let match

  while ((match = codeBlockRegex.exec(content)) !== null) {
    const language = match[1] || ''
    const codeContent = match[2].trim()
    
    codes.push({
      language,
      content: codeContent
    })
  }

  if (codes.length > 0) {
    extractedCodes.value = codes
    activeCodeTab.value = '0'
    codeDialogVisible.value = true
  } else {
    ElMessage.warning('未找到代码块')
  }
}

// 获取代码语言
const getCodeLanguage = (code) => {
  if (!code.language) return null
  
  // 语言名称映射
  const languageMap = {
    'js': 'JavaScript',
    'javascript': 'JavaScript',
    'ts': 'TypeScript',
    'typescript': 'TypeScript',
    'html': 'HTML',
    'css': 'CSS',
    'java': 'Java',
    'python': 'Python',
    'py': 'Python',
    'c': 'C',
    'cpp': 'C++',
    'csharp': 'C#',
    'cs': 'C#',
    'php': 'PHP',
    'go': 'Go',
    'rust': 'Rust',
    'ruby': 'Ruby',
    'swift': 'Swift',
    'kotlin': 'Kotlin',
    'sql': 'SQL',
    'shell': 'Shell',
    'bash': 'Bash',
    'json': 'JSON',
    'xml': 'XML',
    'yaml': 'YAML',
    'yml': 'YAML',
    'markdown': 'Markdown',
    'md': 'Markdown',
    'vue': 'Vue'
  }
  
  return languageMap[code.language.toLowerCase()] || code.language
}

// 复制代码
const copyCode = (code) => {
  const textarea = document.createElement('textarea')
  textarea.value = code.content
  document.body.appendChild(textarea)
  textarea.select()
  
  try {
    document.execCommand('copy')
    ElMessage.success('代码已复制到剪贴板')
  } catch (err) {
    ElMessage.error('复制失败，请手动复制')
  } finally {
    document.body.removeChild(textarea)
  }
}

// 下载代码
const downloadCode = (code, index) => {
  // 确定文件扩展名
  let extension = '.txt'
  if (code.language) {
    const extensionMap = {
      'javascript': '.js',
      'js': '.js',
      'typescript': '.ts',
      'ts': '.ts',
      'html': '.html',
      'css': '.css',
      'java': '.java',
      'python': '.py',
      'py': '.py',
      'c': '.c',
      'cpp': '.cpp',
      'csharp': '.cs',
      'cs': '.cs',
      'php': '.php',
      'go': '.go',
      'rust': '.rs',
      'ruby': '.rb',
      'swift': '.swift',
      'kotlin': '.kt',
      'sql': '.sql',
      'shell': '.sh',
      'bash': '.sh',
      'json': '.json',
      'xml': '.xml',
      'yaml': '.yml',
      'yml': '.yml',
      'markdown': '.md',
      'md': '.md',
      'vue': '.vue'
    }
    extension = extensionMap[code.language.toLowerCase()] || '.txt'
  }
  
  // 创建下载链接
  const blob = new Blob([code.content], { type: 'text/plain' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = `code_snippet_${index + 1}${extension}`
  document.body.appendChild(a)
  a.click()
  
  // 清理
  setTimeout(() => {
    document.body.removeChild(a)
    URL.revokeObjectURL(url)
  }, 100)
  
  ElMessage.success('代码已下载')
}

// 重试连接
const retryConnection = () => {
  reconnectFailed.value = false
  reconnectAttempts = 0
  isConnecting.value = true
  
  // 清除重连定时器
  if (reconnectTimer) {
    clearTimeout(reconnectTimer)
    reconnectTimer = null
  }
  
  // 显示重试连接的状态
  ElMessage({
    message: '正在重试连接 AI 服务...',
    type: 'warning',
    duration: 2000,
    showClose: true,
    iconClass: 'el-icon-refresh'
  })
  
  // 关闭之前的连接
  if (ws) {
    ws.close()
  }
  
  // 短暂延迟后初始化WebSocket连接
  setTimeout(() => {
    initWebSocket()
    
    // 设置连接超时
    const connectionTimeout = setTimeout(() => {
      if (!isConnected.value) {
        ElMessage.error('重试连接失败，请尝试手动连接')
        reconnectFailed.value = true
        isConnecting.value = false
      }
    }, 5000) // 5秒超时
    
    // 监听连接状态变化，清除超时
    const unwatch = watch(isConnected, (newVal) => {
      if (newVal) {
        clearTimeout(connectionTimeout)
        ElMessage.success('AI 服务重连成功！')
        isConnecting.value = false
        unwatch() // 取消监听
      }
    })
  }, 500)
}

// 初始化 WebSocket 连接
const initWebSocket = () => {
  if (ws?.readyState === WebSocket.OPEN) {
    isConnecting.value = false
    return
  }

  try {
    // 关闭之前的连接
    if (ws) {
      ws.close()
    }
    
    ws = new WebSocket(props.websocketUrl)

    ws.onopen = () => {
      console.log('WebSocket连接已建立')
      isConnected.value = true
      reconnectFailed.value = false
      reconnectAttempts = 0
      isConnecting.value = false
      
      // 清除重连定时器
      if (reconnectTimer) {
        clearTimeout(reconnectTimer)
        reconnectTimer = null
      }
      
      // 如果有初始提示词且未发送过，则自动发送
      if (props.initialPrompt && !initialPromptSent) {
        sendInitialPrompt()
      }
    }

    ws.onclose = (event) => {
      console.log('WebSocket连接已关闭', event)
      isConnected.value = false
      
      // 如果不是主动关闭，则尝试重连
      if (!event.wasClean) {
        handleReconnect()
      }
    }

    ws.onerror = (error) => {
      console.error('WebSocket错误:', error)
      isConnected.value = false
      isConnecting.value = false
      handleReconnect()
    }

    ws.onmessage = handleMessage
  } catch (error) {
    console.error('创建WebSocket连接错误:', error)
    isConnected.value = false
    isConnecting.value = false
    handleReconnect()
  }
}

// 处理重连逻辑
const handleReconnect = () => {
  if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
    reconnectAttempts++
    const delay = Math.min(1000 * Math.pow(1.5, reconnectAttempts), 30000) // 指数退避策略，最大30秒
    
    console.log(`尝试第 ${reconnectAttempts} 次重连，${delay/1000} 秒后重试`)
    
    if (reconnectTimer) {
      clearTimeout(reconnectTimer)
    }
    
    reconnectTimer = setTimeout(() => {
      if (dialogVisible.value) { // 只有在对话框打开时才重连
        initWebSocket()
      }
    }, delay)
  } else {
    reconnectFailed.value = true
    ElMessage.error('AI 服务连接失败，请手动重试连接')
  }
}

// 监听WebSocket URL变化
watch(() => props.websocketUrl, (newUrl) => {
  if (newUrl && ws?.url !== newUrl) {
    closeWebSocket()
    if (dialogVisible.value) {
      initWebSocket()
    }
  }
})

// 处理收到的消息
const handleMessage = (event) => {
  try {
    const data = JSON.parse(event.data)
    if (data.type === 'reply') {
      if (data.messageType === 'reasoning') {
        // 处理推理过程
        if (messages.value.length > 0 && messages.value[messages.value.length - 1].role === 'reasoning') {
          // 更新现有的推理消息
          messages.value[messages.value.length - 1].content += data.content
        } else {
          // 添加新的推理消息
          messages.value.push({
            role: 'reasoning',
            content: data.content
          })
        }
        scrollToBottom()
      } else if (data.messageType === 'content') {
        if (data.content) {
          // 更新最后一条AI消息，或添加新消息
          if (messages.value.length > 0 && messages.value[messages.value.length - 1].role === 'assistant') {
            messages.value[messages.value.length - 1].content += data.content
          } else {
            messages.value.push({
              role: 'assistant',
              content: data.content,
              timestamp: new Date().toISOString()
            })
          }
          scrollToBottom()
        } else {
          isThinking.value = false
        }
      }
    } else if (data.type === 'done') {
      // 响应完成
      isThinking.value = false
    }
  } catch (error) {
    console.error('处理消息错误:', error)
    handleError()
  }
}

// 发送初始提示词
const sendInitialPrompt = () => {
  if (!props.initialPrompt || !isConnected.value || initialPromptSent) return
  
  // 添加用户消息
  messages.value.push({
    role: 'user',
    content: props.initialPrompt,
    timestamp: new Date().toISOString()
  })
  scrollToBottom()

  let ms = [];
  ms.push({
    role: 'user',
    content: props.initialPrompt
  })

  isThinking.value = true
  initialPromptSent = true

  // 发送消息 prompt
  const msg = {
    type: 'batchV3',
    message: JSON.stringify(ms),
    model: selectedModel.value,
    stream: true
  }
  
  try {
    ws.send(JSON.stringify(msg))
  } catch (error) {
    console.error('发送初始提示词错误:', error)
    handleError()
  }
}

// 发送消息
const handleSend = () => {
  const message = userInput.value.trim()
  if (!message || isThinking.value || !isConnected.value) return

  // 添加用户消息
  messages.value.push({
    role: 'user',
    content: message,
    timestamp: new Date().toISOString()
  })
  userInput.value = ''
  scrollToBottom()

  isThinking.value = true

  // 准备消息历史（如果是连续对话模式）
  let ms = [];
  
  if (continuousMode.value) {
    // 连续对话模式：包含历史消息
    ms = messages.value
      .filter(msg => msg.role === 'user' || msg.role === 'assistant')
      .map(msg => ({
        role: msg.role,
        content: msg.content
      }))
  } else {
    // 非连续对话模式：只包含当前消息
    ms = [{
      role: 'user',
      content: message
    }]
  }

  // 发送消息
  const msg = {
    type: 'batchV3',
    message: JSON.stringify(ms),
    model: selectedModel.value,
    stream: true
  }
  
  try {
    ws.send(JSON.stringify(msg))
  } catch (error) {
    console.error('发送消息错误:', error)
    handleError()
  }
}

// 错误处理
const handleError = () => {
  ElMessage.error('发送消息失败，请重试')
  isThinking.value = false
}

// 关闭WebSocket连接
const closeWebSocket = () => {
  if (reconnectTimer) {
    clearTimeout(reconnectTimer)
    reconnectTimer = null
  }
  
  if (ws) {
    ws.close()
    ws = null
  }
}

// 关闭对话框
const handleClose = () => {
  if (isThinking.value) {
    ElMessage.warning('正在等待AI响应，请稍候...')
    return
  }
  closeWebSocket()
  messages.value = []
  userInput.value = ''
  initialPromptSent = false
  reconnectFailed.value = false
  dialogVisible.value = false
}

// 监听对话框显示状态
watch(() => props.modelValue, (newVal) => {
  if (newVal && !isConnected.value) {
    initWebSocket()
  }
})

// 监听初始提示词变化
watch(() => props.initialPrompt, (newVal) => {
  if (newVal && isConnected.value && !initialPromptSent) {
    sendInitialPrompt()
  }
})

// 组件挂载时初始化
onMounted(() => {
  if (dialogVisible.value) {
    initWebSocket()
  }
})

// 组件卸载时清理
onUnmounted(() => {
  closeWebSocket()
})

// 格式化时间
const formatTime = (timestamp) => {
  const date = new Date(timestamp)
  return date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})
}

// 显示对话上下文
const showContextDialog = () => {
  if (messages.value.length < 2) {
    ElMessage.warning('对话历史不足，无法显示上下文')
    return
  }
  contextDialogVisible.value = true
}

// 重新发送消息
const resendMessage = (content) => {
  // 添加用户消息
  messages.value.push({
    role: 'user',
    content: content,
    timestamp: new Date().toISOString()
  })
  scrollToBottom()

  isThinking.value = true

  // 准备消息历史（如果是连续对话模式）
  let ms = [];
  
  if (continuousMode.value) {
    // 连续对话模式：包含历史消息
    ms = messages.value
      .filter(msg => msg.role === 'user' || msg.role === 'assistant')
      .map(msg => ({
        role: msg.role,
        content: msg.content
      }))
  } else {
    // 非连续对话模式：只包含当前消息
    ms = [{
      role: 'user',
      content: content
    }]
  }

  // 发送消息
  const msg = {
    type: 'batchV3',
    message: JSON.stringify(ms),
    model: selectedModel.value,
    stream: true
  }
  
  try {
    ws.send(JSON.stringify(msg))
  } catch (error) {
    console.error('重新发送消息错误:', error)
    handleError()
  }
}

// 编辑后重发
const editAndResend = (content) => {
  userInput.value = content
  ElMessage.success('消息已复制到输入框，您可以编辑后重新发送')
  // 滚动到输入框
  nextTick(() => {
    const textarea = document.querySelector('.input-textarea textarea')
    if (textarea) {
      textarea.focus()
    }
  })
}

// 高亮代码
const highlightCode = (code) => {
  if (!code.language) return hljs.highlightAuto(code.content).value;
  
  try {
    return hljs.highlight(code.content, { 
      language: code.language, 
      ignoreIllegals: true 
    }).value;
  } catch (e) {
    console.error("代码高亮错误:", e);
    return hljs.highlightAuto(code.content).value;
  }
}

// 终止生成
const stopGeneration = () => {
  if (!isThinking.value) return;
  
  try {
    // 关闭当前WebSocket连接
    if (ws && ws.readyState === WebSocket.OPEN) {
      // 先将状态更新为非思考状态
      isThinking.value = false;
      
      // 关闭当前连接
      ws.close();
      
      // 如果当前没有AI回复，添加一个提示消息
      if (messages.value.length === 0 || messages.value[messages.value.length - 1].role !== 'assistant') {
        messages.value.push({
          role: 'assistant',
          content: '生成已被用户终止。',
          timestamp: new Date().toISOString()
        });
      } else {
        // 在现有回复后添加终止提示
        messages.value[messages.value.length - 1].content += '\n\n*生成已被用户终止*';
      }
      
      // 重新建立WebSocket连接
      setTimeout(() => {
        initWebSocket();
      }, 500); // 短暂延迟后重新连接
      
      ElMessage.info('已停止AI回答生成');
    }
  } catch (error) {
    console.error('终止生成错误:', error);
    ElMessage.error('终止生成失败');
    // 尝试重新连接
    setTimeout(() => {
      initWebSocket();
    }, 1000);
  }
};

// 手动连接
const manualConnect = () => {
  // 清除之前的连接状态
  reconnectFailed.value = false
  reconnectAttempts = 0
  isConnecting.value = true
  
  // 清除重连定时器
  if (reconnectTimer) {
    clearTimeout(reconnectTimer)
    reconnectTimer = null
  }
  
  // 显示连接中的状态
  ElMessage({
    message: '正在手动连接 AI 服务...',
    type: 'info',
    duration: 2000,
    showClose: true,
    iconClass: 'el-icon-loading'
  })
  
  // 关闭之前的连接
  if (ws) {
    ws.close()
  }
  
  // 短暂延迟后初始化WebSocket连接，让用户感知到连接过程
  setTimeout(() => {
    initWebSocket()
    
    // 设置连接超时
    const connectionTimeout = setTimeout(() => {
      if (!isConnected.value) {
        ElMessage.error('连接超时，请检查网络后再试')
        reconnectFailed.value = true
        isConnecting.value = false
      }
    }, 5000) // 5秒超时
    
    // 监听连接状态变化，清除超时
    const unwatch = watch(isConnected, (newVal) => {
      if (newVal) {
        clearTimeout(connectionTimeout)
        ElMessage.success('AI 服务连接成功！')
        isConnecting.value = false
        unwatch() // 取消监听
      }
    })
  }, 500)
}
</script>

<style scoped>
.ai-chat-dialog :deep(.el-dialog__body) {
  padding: 0;
}

.ai-chat-dialog :deep(.el-dialog__header) {
  padding: 0;
  margin: 0;
}

.ai-chat-dialog :deep(.el-dialog) {
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1);
}

.dialog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  background: linear-gradient(135deg, #409eff, #67c23a);
  color: white;
}

.dialog-title {
  display: flex;
  align-items: center;
  font-size: 18px;
  font-weight: 600;
}

.title-icon {
  margin-right: 10px;
  font-size: 22px;
}

.close-btn {
  color: white;
  background-color: rgba(255, 255, 255, 0.2);
  border: none;
  transition: background-color 0.3s;
}

.close-btn:hover {
  background-color: rgba(255, 255, 255, 0.3);
  color: white;
}

.chat-container {
  display: flex;
  flex-direction: column;
  height: 70vh;
  padding: 20px;
}

.chat-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid #ebeef5;
}

.connection-status {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  background-color: #f5f7fa;
  border-radius: 20px;
  color: #909399;
  flex: 1;
  transition: all 0.3s ease;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
  position: relative;
  overflow: hidden;
}

.connection-status.connected {
  background-color: #f0f9eb;
  color: #67c23a;
}

.connection-status::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
  transform: translateX(-100%);
  animation: shimmer 2s infinite;
  pointer-events: none;
}

.connection-status.connected::before {
  background: linear-gradient(90deg, transparent, rgba(103, 194, 58, 0.2), transparent);
}

@keyframes shimmer {
  100% {
    transform: translateX(100%);
  }
}

.status-icon {
  margin-right: 8px;
  font-size: 16px;
  animation: blink 2s infinite ease-in-out;
}

.connection-status.connected .status-icon {
  animation: pulse 2s infinite;
}

.connection-actions {
  display: flex;
  gap: 8px;
  margin-left: auto;
  animation: slideIn 0.5s ease;
}

.action-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  border-radius: 16px;
  padding: 6px 12px;
  transition: all 0.3s ease;
  transform-origin: center;
}

.action-btn:hover {
  transform: translateY(-2px) scale(1.05);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.action-btn:active {
  transform: translateY(1px) scale(0.98);
}

.action-icon {
  animation: pulse 2s infinite linear;
  margin-right: 4px;
}

.retry-btn {
  background-color: #409eff;
  border-color: #409eff;
}

.retry-btn:hover {
  background-color: #66b1ff;
  border-color: #66b1ff;
}

.retry-btn .action-icon {
  animation: rotate 2s infinite linear;
}

.manual-connect-btn {
  background-color: #67c23a;
  border-color: #67c23a;
}

.manual-connect-btn:hover {
  background-color: #85ce61;
  border-color: #85ce61;
}

.manual-connect-btn .action-icon {
  animation: pulse 2s infinite;
}

.model-selector {
  display: flex;
  align-items: center;
  margin-left: 16px;
  background-color: #f5f7fa;
  padding: 6px 12px;
  border-radius: 20px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
}

.model-label {
  margin-right: 8px;
  white-space: nowrap;
  color: #606266;
  font-weight: 500;
}

.model-select {
  width: 160px;
}

.chat-mode-switch {
  display: flex;
  align-items: center;
  margin-left: 16px;
  background-color: #f5f7fa;
  padding: 6px 12px;
  border-radius: 20px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
}

.mode-label {
  margin-right: 8px;
  white-space: nowrap;
  color: #606266;
  font-weight: 500;
}

.context-btn {
  margin-left: 8px;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  border-radius: 12px;
  margin-bottom: 16px;
  scroll-behavior: smooth;
}

.message {
  margin-bottom: 20px;
  display: flex;
  align-items: flex-start;
  animation: fadeIn 0.3s ease;
}

.user-message {
  flex-direction: row-reverse;
}

.ai-message {
  flex-direction: row;
}

.avatar {
  margin: 0 10px;
}

.user-avatar {
  background-color: #409eff;
  color: white;
}

.ai-avatar {
  background: linear-gradient(135deg, #67c23a, #409eff);
  color: white;
}

.message-content {
  max-width: 70%;
  padding: 12px 16px;
  border-radius: 18px;
  word-break: break-word;
  position: relative;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transition: all 0.3s ease;
}

.reasoning-message {
  flex-direction: column;
  align-items: flex-start;
  margin-left: 56px;
  max-width: 90%;
}

.reasoning-container {
  width: 100%;
  background-color: #f8faff;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid rgba(64, 158, 255, 0.1);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
}

.reasoning-header {
  display: flex;
  align-items: center;
  gap: 8px;
  background: linear-gradient(to right, #f2f6ff, #f8faff);
  padding: 10px 14px;
  font-weight: 500;
  color: #409eff;
  border-bottom: 1px solid rgba(64, 158, 255, 0.1);
}

.reasoning-header .el-icon {
  font-size: 16px;
  color: #409eff;
}

.reasoning-text {
  padding: 14px 16px;
  line-height: 1.6;
  white-space: pre-wrap;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 0.9em;
  color: #5a6478;
  background-color: #f8faff;
}

.thinking-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: white;
  min-width: 60px;
  min-height: 40px;
  padding: 12px 16px;
  border-left: 3px solid #409eff;
}

.thinking-indicator-container {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.thinking-status {
  font-size: 14px;
  color: #409eff;
  font-weight: 500;
}

.typing-indicator {
  display: flex;
  align-items: center;
}

.typing-indicator span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #409eff;
  margin: 0 2px;
  animation: pulse 1.4s infinite;
  opacity: 0.7;
}

.typing-indicator span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
  animation-delay: 0.4s;
}

.message-time {
  font-size: 0.75em;
  color: #909399;
  margin-top: 6px;
  text-align: right;
}

.user-message .message-time {
  text-align: left;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #909399;
}

.empty-icon {
  font-size: 48px;
  margin-bottom: 16px;
  color: #dcdfe6;
}

.empty-state p {
  margin: 8px 0;
  font-size: 16px;
}

.empty-hint {
  color: #c0c4cc;
  font-size: 14px;
}

.chat-input {
  margin-top: auto;
  background-color: white;
  border-radius: 12px;
  padding: 16px;
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
}

.input-textarea {
  border-radius: 8px;
  resize: none;
  transition: all 0.3s;
}

.input-textarea :deep(.el-textarea__inner) {
  border-radius: 8px;
  padding: 12px;
  min-height: 80px;
  transition: all 0.3s;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
}

.input-textarea :deep(.el-textarea__inner:focus) {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.input-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 12px;
}

.left-actions {
  display: flex;
  gap: 10px;
}

.right-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.action-btn {
  border-radius: 20px;
  padding: 8px 16px;
  transition: all 0.3s;
}

.action-btn:hover {
  transform: translateY(-2px);
}

.hint {
  color: #909399;
  font-size: 12px;
  background-color: #f5f7fa;
  padding: 4px 8px;
  border-radius: 12px;
}

.send-btn {
  border-radius: 24px;
  padding: 10px 20px;
  font-weight: 500;
  transition: all 0.3s;
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}

.send-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.4);
}

.send-icon {
  margin-right: 6px;
}

/* 代码提取对话框样式 */
.code-extract-dialog :deep(.el-dialog),
.context-dialog :deep(.el-dialog) {
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1);
}

.code-extract-dialog :deep(.el-dialog__header),
.context-dialog :deep(.el-dialog__header) {
  padding: 16px 20px;
  background: linear-gradient(135deg, #409eff, #67c23a);
  color: white;
  margin: 0;
}

.code-extract-dialog :deep(.el-dialog__title),
.context-dialog :deep(.el-dialog__title) {
  color: white;
  font-weight: 600;
}

.code-extract-dialog :deep(.el-dialog__headerbtn .el-dialog__close),
.context-dialog :deep(.el-dialog__headerbtn .el-dialog__close) {
  color: white;
}

.code-tabs {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.code-tabs :deep(.el-tabs__header) {
  margin-bottom: 0;
  padding: 10px 10px 0;
}

.code-tabs :deep(.el-tabs__content) {
  flex: 1;
  overflow: hidden;
  padding: 0 10px 10px;
}

.code-tabs :deep(.el-tab-pane) {
  height: 100%;
}

.code-block-wrapper {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.code-block-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 16px;
  background-color: #f5f7fa;
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  border: 1px solid #e4e7ed;
  border-bottom: none;
  flex-shrink: 0;
}

.code-language {
  font-weight: 500;
  color: #606266;
}

.code-actions {
  display: flex;
  gap: 8px;
}

.code-action-btn {
  display: flex;
  align-items: center;
  gap: 4px;
}

.code-content-wrapper {
  flex: 1;
  overflow: hidden;
  position: relative;
  border: 1px solid #e4e7ed;
  border-top: none;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
}

.code-content {
  margin: 0;
  padding: 16px;
  background-color: #f6f8fa;
  height: 100%;
  max-height: 500px;
  overflow-y: auto;
  overflow-x: auto;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 14px;
  line-height: 1.5;
  color: #24292e;
  white-space: pre-wrap;
  box-sizing: border-box;
  border-radius: 0 0 8px 8px;
}

.code-content .hljs {
  background-color: transparent;
  padding: 0;
  white-space: pre-wrap;
  word-break: break-word;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes pulse {
  0% {
    opacity: 0.6;
    transform: scale(1);
  }
  50% {
    opacity: 1;
    transform: scale(1.2);
  }
  100% {
    opacity: 0.6;
    transform: scale(1);
  }
}

@keyframes blink {
  0%, 100% {
    opacity: 0.6;
  }
  50% {
    opacity: 0.2;
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateX(-20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.message-fade-enter-active,
.message-fade-leave-active {
  transition: all 0.3s ease;
}

.message-fade-enter-from,
.message-fade-leave-to {
  opacity: 0;
  transform: translateY(10px);
}

/* Markdown styling */
.markdown-body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  word-wrap: break-word;
  color: #303133;
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4 {
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
  color: #1f2d3d;
}

.markdown-body h1 {
  font-size: 1.5em;
}

.markdown-body h2 {
  font-size: 1.3em;
}

.markdown-body h3 {
  font-size: 1.1em;
}

.markdown-body p {
  margin-top: 0;
  margin-bottom: 16px;
}

.markdown-body a {
  color: #409eff;
  text-decoration: none;
}

.markdown-body a:hover {
  text-decoration: underline;
}

.markdown-body ul,
.markdown-body ol {
  padding-left: 2em;
  margin-top: 0;
  margin-bottom: 16px;
}

.markdown-body blockquote {
  margin: 0;
  padding: 0 1em;
  color: #6a737d;
  border-left: 0.25em solid #dfe2e5;
}

.markdown-body pre {
  background-color: #f6f8fa;
  border-radius: 8px;
  padding: 16px;
  overflow: auto;
  margin-bottom: 16px;
  box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.1);
  position: relative;
}

.markdown-body pre::after {
  content: attr(data-lang);
  position: absolute;
  top: 0;
  right: 0;
  color: #fff;
  font-size: 0.75em;
  font-weight: 600;
  padding: 5px 10px;
  text-transform: uppercase;
  border-bottom-left-radius: 5px;
  background-color: rgba(0, 0, 0, 0.3);
}

.markdown-body .hljs {
  background-color: transparent;
  padding: 0;
  color: inherit;
}

/* 自定义代码高亮样式 */
.markdown-body .hljs-keyword,
.markdown-body .hljs-selector-tag,
.markdown-body .hljs-subst {
  color: #d73a49;
  font-weight: bold;
}

.markdown-body .hljs-string,
.markdown-body .hljs-doctag,
.markdown-body .hljs-regexp {
  color: #032f62;
}

.markdown-body .hljs-title,
.markdown-body .hljs-section,
.markdown-body .hljs-selector-id {
  color: #6f42c1;
  font-weight: bold;
}

.markdown-body .hljs-comment,
.markdown-body .hljs-quote {
  color: #6a737d;
  font-style: italic;
}

.markdown-body .hljs-number,
.markdown-body .hljs-literal,
.markdown-body .hljs-variable,
.markdown-body .hljs-template-variable,
.markdown-body .hljs-tag .hljs-attr {
  color: #005cc5;
}

.markdown-body .hljs-built_in,
.markdown-body .hljs-builtin-name,
.markdown-body .hljs-type,
.markdown-body .hljs-params {
  color: #e36209;
}

.markdown-body .hljs-attribute,
.markdown-body .hljs-name {
  color: #22863a;
  font-weight: bold;
}

.markdown-body .hljs-symbol,
.markdown-body .hljs-bullet {
  color: #005cc5;
}

.markdown-body .hljs-tag,
.markdown-body .hljs-meta {
  color: #22863a;
}

.markdown-body .hljs-addition {
  color: #22863a;
  background-color: #f0fff4;
}

.markdown-body .hljs-deletion {
  color: #b31d28;
  background-color: #ffeef0;
}

/* 对话上下文样式 */
.context-dialog :deep(.el-dialog__body) {
  padding: 20px;
  max-height: 70vh;
  overflow: hidden;
}

.context-info {
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
}

.context-description {
  color: #606266;
  font-size: 14px;
  margin: 0;
  flex-shrink: 0;
}

.context-messages-wrapper {
  flex: 1;
  overflow: hidden;
  border: 1px solid #ebeef5;
  border-radius: 8px;
}

.context-messages {
  height: 100%;
  max-height: 400px;
  overflow-y: auto;
}

.context-message {
  padding: 12px;
  border-bottom: 1px solid #ebeef5;
}

.context-message:last-child {
  border-bottom: none;
}

.context-message-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 8px;
}

.context-role {
  font-weight: 600;
  color: #303133;
}

.context-time {
  color: #909399;
  font-size: 12px;
}

.context-content {
  color: #606266;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 14px;
  line-height: 1.5;
  background-color: #f5f7fa;
  padding: 8px;
  border-radius: 4px;
}

.context-tokens {
  color: #909399;
  font-size: 12px;
  text-align: right;
  padding-top: 8px;
  border-top: 1px dashed #ebeef5;
  flex-shrink: 0;
}

.code-extract-dialog :deep(.el-dialog__body) {
  padding: 0;
  height: 70vh;
  overflow: hidden;
}

.markdown-body code {
  background-color: rgba(27, 31, 35, 0.05);
  border-radius: 3px;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 85%;
  margin: 0;
  padding: 0.2em 0.4em;
}

.markdown-body pre code {
  background-color: transparent;
  padding: 0;
  border-radius: 0;
}

.markdown-body table {
  border-collapse: collapse;
  width: 100%;
  margin-bottom: 16px;
}

.markdown-body table th,
.markdown-body table td {
  padding: 6px 13px;
  border: 1px solid #dfe2e5;
}

.markdown-body table tr {
  background-color: #fff;
  border-top: 1px solid #c6cbd1;
}

.markdown-body table tr:nth-child(2n) {
  background-color: #f6f8fa;
}

.markdown-body img {
  max-width: 100%;
  box-sizing: content-box;
  border-radius: 4px;
}

.stop-btn {
  margin-left: 16px;
  border-radius: 20px;
  display: flex;
  align-items: center;
  gap: 4px;
  background-color: #f56c6c;
  border-color: #f56c6c;
  box-shadow: 0 2px 6px rgba(245, 108, 108, 0.2);
  transition: all 0.3s ease;
}

.stop-btn:hover {
  background-color: #f78989;
  border-color: #f78989;
  box-shadow: 0 4px 12px rgba(245, 108, 108, 0.3);
  transform: translateY(-2px);
}

.message-actions {
  position: absolute;
  top: 8px;
  right: 8px;
  opacity: 0;
  transition: opacity 0.3s;
  z-index: 10;
  display: flex;
  gap: 5px;
}

.ai-content:hover + .message-actions,
.message-actions:hover {
  opacity: 1;
}

.user-content {
  color: #333;
  border-top-right-radius: 4px;
  position: relative;
}

.user-message-actions {
  position: absolute;
  bottom: 8px;
  left: 8px;
  opacity: 0;
  transition: opacity 0.3s;
  z-index: 10;
  display: flex;
  gap: 5px;
}

.user-message-actions .el-button {
  background-color: rgba(255, 255, 255, 0.2);
  border: none;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
  transform: scale(0.85);
}

.user-message-actions .el-button:hover {
  background-color: rgba(255, 255, 255, 0.3);
  transform: scale(0.9);
}

.user-content:hover .user-message-actions {
  opacity: 1;
}

.ai-content {
  background-color: white;
  color: #303133;
  border-top-left-radius: 4px;
}
</style> 